﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;

namespace ArtheaEngine.Model
{
    /// <summary>
    /// Implementation of board.
    /// </summary>
    public abstract partial class Board
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="Board"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="description">The description.</param>
        /// <param name="read">The read.</param>
        /// <param name="write">The write.</param>
        public Board(string name, string description, BoardPermissions read, BoardPermissions write)
        {
            Name = name;
            Description = description;
            WritePermission = write;
            ReadPermission = read;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Board"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="description">The description.</param>
        public Board(string name, string description)
            : this(name, description, BoardPermissions.None, BoardPermissions.None)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Board"/> class.
        /// </summary>
        public Board()
        {
        }

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString()
        {
            return Name;
        }

        /// <summary>
        /// Determines whether a specific note can be read on this board.
        /// </summary>
        /// <param name="note">The note.</param>
        /// <param name="player">The player.</param>
        /// <returns>
        /// 	<c>true</c> if this the specified note can be read on this board; otherwise, <c>false</c>.
        /// </returns>
        private bool NoteReadableBy(Note note, Character player)
        {
            return ((ReadPermission & BoardPermissions.Personal) == 0 ||
                    note.From == player.Name ||
                    note.To.Contains(player.Name));
        }

        /// <summary>
        /// Returns the number of unread notes for a player on this board.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <returns>the number of unread notes</returns>
        public int CountUnreadNotes(Player player)
        {
            if (ReadPermission.Has(BoardPermissions.Admin) && (player.Account.Flags.And(Account.Admin)))
                return 0;

            int count = 0;

            foreach (Note n in Notes)
            {
                if (player.HasReadNote(n) ||
                    !NoteReadableBy(n, player))
                {
                    continue;
                }

                ++count;
            }

            return count;
        }

        /// <summary>
        /// Gets the next unread.
        /// </summary>
        /// <param name="player">The player.</param>
        /// <returns></returns>
        public Note GetNextUnreadNote(Player player)
        {
            if (ReadPermission.Has(BoardPermissions.Admin) && !player.Account.Flags.And(Account.Admin))
                return null;

            foreach (Note n in Notes)
            {
                if (player.HasReadNote(n) ||
                    !NoteReadableBy(n, player))
                {
                    continue;
                }

                return n;
            }

            return null;
        }

        /// <summary>
        /// Shows the note list to.
        /// </summary>
        /// <param name="player">The player.</param>
        public void ShowNoteListTo(Player player)
        {
            StringCollection columns = new StringCollection();

            var count = 0;

            foreach(var note in Notes)
            {
                if (!NoteReadableBy(note, player))
                    continue;

                columns.Add(string.Format("{0}{1,-2}> {2} ({3})",
                                          player.HasReadNote(note) ? "~R*~x" : " ",
                                          (count + 1), note.Subject, note.From));
                count++;
            }

            Columns.Show(player, 2, columns);
        }
    }

    public partial class BoardPermissionWrapper
    {
        public BoardPermissions EnumValue
        {
            get { return (BoardPermissions)Value; }
            set { Value = (int)value; }
        }

        public static implicit operator BoardPermissionWrapper(BoardPermissions value)
        {
            return new BoardPermissionWrapper { Value = (int)value };
        }

        public static implicit operator BoardPermissions(BoardPermissionWrapper value)
        {
            if (value == null) return default(BoardPermissions);

            return value.EnumValue;
        }

        public bool Has(BoardPermissions perm)
        {
            return (EnumValue & perm) != 0;
        }
    }

    [Flags]
    public enum BoardPermissions
    {
        /// <summary>
        /// No permissions, all can read/write
        /// </summary>
        None,
        /// <summary>
        /// Only person in to or from fields
        /// </summary>
        Personal,
        /// <summary>
        /// admin can read/write
        /// </summary>
        Admin
    }
}

